home *** CD-ROM | disk | FTP | other *** search
- #!/usr/bin/perl
-
- use 5.005;
-
- $VERSION = 1.0;
-
- # Copyright Marc Lehmann <pcg@goof.com>
- #
- # This is distributed under the GPL (see COPYING.GNU for details).
-
- =cut
-
- =head1 NAME
-
- scm2scm - convert script-fu to script-fu
-
- =head1 SYNOPSIS
-
- scm2scm [-d] [-t translation]... filename.scm...
-
- =head1 DESCRIPTION
-
- This perl-script can be used to upgrade existing script-fu-scripts to
- newer gimp API's.
-
- =head1 EXAMPLES
-
- Convert all script-fu scripts in the current directory from the 1.0 to the
- 1.2 API (creating new files with the extension .sc2):
-
- scm2scm -t 1.2 *.scm
-
- Generate a diff containing the required changes from the 1.0
- to the 1.1-API:
-
- scm2scm -d -t 1.1 test.scm
-
- =head1 SWITCHES
-
- =over 4
-
- =item -d
-
- generate a unified diff on stdout
-
- =item -t translation id
-
- specify a translation id, can be one of (run scm2scm without arguments
- to see the full list)
-
- I<api1> api-mega-break-patch #1
- I<api2> api-mega-rename-patch #1 (NYI)
-
- I<1.1> 1.0 -> 1.1 (not fully implemented)
-
- I<1.2> 1.0 -> 1.2 (not fully implemented)
-
- =back
-
- =head1 AUTHOR
-
- Marc Lehmann <pcg@goof.com>
-
- =head1 SEE ALSO
-
- gimp(1), L<Gimp>.
-
- =cut
-
- # Fixes names of functions by swapping last two parts of the name
- # eg. gimp-image-disable-undo becomes gimp-image-undo-disable
- # Whitespace is preserved(!)
- sub swap_last_two {
- my($a,$f,$t1,$t2,@t)=@_;
- $f->[1] =~ s/(\w+)-(\w+)-(\w+)-(\w+)/$1-$2-$4-$3/;
- ($a,$f,new token($t1->[0],$t1->[1],$t2->[1]),@t);
- }
-
- # drop the first argument, while preserving correct whitespace(!)
- sub drop_1st {
- my($a,$f,$t1,$t2,@t)=@_;
- ($a,$f,new token($t1->[0],$t2->[1],$t2->[2]),@t);
- }
-
- # "nicify" plug-in constants
- sub plug_in_constant {
- my($a,$f,$t1,$t2,@t)=@_;
- my $n = $t2->[1];
- $n==0 and $n = "RUN_NONINTERACTIVE";
- ($a,$f,new token($t1->[0],$n,$t2->[2]),@t);
- }
-
- # every hash value consists of an array of specifications, each
- # one has the form ["regexp", codref_to_call], or a string (another translation
- # name)
- %translation = (
- 'api1' =>
- [
- [
- "^(gimp-airbrush|gimp-blend|gimp-brightness-contrast|gimp-bucket-fill|".
- "gimp-by-color-select|gimp-channel-ops-offset|gimp-clone|gimp-color-balance|".
- "gimp-color-picker|gimp-convolve|gimp-curves-explicit|gimp-curves-spline|".
- "gimp-desaturate|gimp-edit-clear|gimp-edit-copy|gimp-edit-cut|gimp-edit-fill|".
- "gimp-edit-paste|gimp-edit-stroke|gimp-equalize|gimp-eraser|".
- "gimp-eraser-extended|gimp-flip|gimp-fuzzy-select|gimp-histogram|".
- "gimp-hue-saturation|gimp-invert|gimp-levels|gimp-paintbrush|".
- "gimp-paintbrush-extended|gimp-pencil|gimp-perspective|gimp-posterize|".
- "gimp-rotate|gimp-scale|gimp-selection-float|gimp-selection-layer-alpha|".
- "gimp-selection-load|gimp-shear|gimp-threshold)\$",
- \&drop_1st
- ]
- ],
- 'api2' =>
- [
- [
- "^(gimp-image-disable-undo|gimp-image-enable-undo)\$",
- \&swap_last_two
- ]
- ],
- '1.1' => ['nice','api1','api2'],
- '1.2' => ['nice','api1','api2'],
- 'nice'=> [],#["^(plug-in-|file-|gimp-file-)", \&plug_in_constant]],
- );
-
- $gen_diff=0;
- @trans = ();
-
- package token;
-
- sub new {
- my $type = shift;
- bless [@_],$type;
- }
-
- package main;
-
- my $stream; # the stream to tokenize from
- my $word; # the current token-word
- my $tok; # current token
-
- # parses a new token [ws, tok, ws]
- sub get() {
- my($ws1,$ctk,$ws2);
- # could be wrapped into one regex
- $ws1 = $stream=~s/^((?:\s*(?:(;[^\n]*\n))?)*)// ? $1 : die;
- $ctk = $stream=~s/^(\(
- |\)
- |"(?:[^"]+|\\")*"
- |'(?:[^()]+)
- |[^ \t\r\n()]+
- )
- (?:[ \t]*(?=\n))?//x ? $1 : undef;
- $ws2 = $stream=~s/^([ \t]*;[^\n]*\n)// ? $1 : "";
- $word=$ctk;
-
- # print "TOKEN:$ws1:$ctk:$ws2\n";
- $tok=new token($ws1,$ctk,$ws2);
- }
-
- # returns a parse tree, which is an array
- # of [token, token...] refs.
- sub parse() {
- my @toks;
- $depth++;
- for(;;) {
- # print "$depth: $word\n";
- if ($word eq "(") {
- my $t = $tok; get;
- my @t = &parse;
- $word eq ")" or die "missing right parenthesis (got $word)\n";
- push(@toks,[$t,@t,$tok]); get;
- } elsif ($word eq ")") {
- $depth--;
- return @toks;
- } elsif (!defined $word) {
- $depth--;
- return @toks;
- } else {
- push(@toks,$tok);
- get;
- }
- }
- }
-
- sub parse_scheme {
- get;
- my @t = parse;
- (@t,$tok);
- }
-
- # dumb dump of the tree structure
- sub dump_tree {
- my $d=shift;
- print "$d",scalar@_;
- for(@_) {
- if (isa($_,token)) {
- print " [$_->[1]]";
- } else {
- print " *";
- }
- }
- print "\n";
- for(@_) {
- if(!isa($_,token)) {
- dump_tree ("$d ",@$_);
- }
- }
- }
-
- sub toks2scheme {
- my $func = shift;
- if ($func->[1] eq "(") {
- my $close = shift;
- # func2scheme @_;
- } else {
- }
- while(@_) {
- my @toks = shift;
- my ($unused,$t,$ws1)=$toks[0]
- }
-
- }
-
- sub tree2scheme {
- join ("",map isa($_,token) ? @$_ : tree2scheme(@$_),@_);
- }
-
- sub scheme2perl {
- for(@_) {
- local $_ = shift;
- print scalar@_,">\n";
- local *_ = \$_[0];
- print "$_=\n";
- if (isa($_,token)) {
- my $t = $_->[1];
- $_->[0] =~ s/^(\s*);/$1#/mg;
- $_->[1] =~ s/^(\s*);/$1#/mg;
- if ($t eq "define") {
- $_->[1] = "sub";
- splice @{$_[$i+1]},2,-1,new token "","{","";
- $_[$i+2]
- } elsif ($t =~ /[()]/) {
- $_->[1] = "";
- } else {
- $_[0] = [
- new token ("[",$_->[0],"<"),
- new token ("",$_->[1],">"),
- new token ("",$_->[2],"]"),
- ];
- }
- } else {
- scheme2perl(@$_);
- }
- shift; print scalar@_,"<\n";
- }
- }
-
- # translate functions, sorry folks, this function is write-only!
- sub translate {
- my $v=shift;
- my @t=@_;
- if (isa($t[0],token)) {
- for(@$v) {
- if ($t[1][1] =~ $_->[0]) {
- @t=$_->[1]->(@t);
- }
- }
- }
- for(@t) {
- $_=[translate($v,@$_)] unless isa($_,token);
- }
- @t;
- }
-
- sub dofile {
- my($in,$out)=@_;
-
- open IN,"$in" or die "unable to open '$in' for reading: $!";
- { local $/; $stream = <IN> }
- close IN;
-
- my @prog = parse_scheme;
-
- if (@trans) {
- my $changed;
- do {
- $changed=0;
- @trans = map {
- if (!ref $_) {
- $changed=1;
- @{$translation{$_}};
- } else {
- $_;
- }
- } @trans;
- } while($changed);
- @prog = translate ([@trans],@prog);
- }
-
- open OUT,"$out" or die "unable to open '$out' for writing: $!";
- #scheme2perl(@prog);
- print OUT tree2scheme(@prog);
- close OUT;
- }
-
- *isa = \&UNIVERSAL::isa;
-
- sub usage {
- print STDERR "Script-Fu to Script-Fu Translater 1.1.1\n";
- print STDERR "Usage: $0 [-d] [-t translation] file.scm ...\n";
- print STDERR "available translations are: @{[keys %translation]}\n";
- exit(1);
- }
-
- while($ARGV[0]=~/^-(.)$/) {
- shift;
- if ($1 eq "d") {
- $gen_diff=1;
- } elsif ($1 eq "t") {
- push(@trans,shift);
- } else {
- print STDERR "unknown switch '$1'\n";
- }
- }
- @ARGV or usage;
-
- for $x (@ARGV) {
- my $y;
- if ($gen_diff) {
- $y="| echo Index: '$x' && diff -u '$x' -";
- } else {
- ($y=$x)=~s/\.scm/.sc2/i or die "source file '$x' has no .scm extension";
- $y=">$y\0";
- }
- dofile("<$x\0",$y);
- }
-
-